package com.hhyx.execl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hhyx.execl.handler.BusinessException;
import com.hhyx.execl.model.entity.Before;
import com.hhyx.execl.model.entity.SystemMessage;
import com.hhyx.execl.model.result.ReadFileResult;
import com.hhyx.execl.service.BeforeFileService;
import com.hhyx.execl.service.FileImportService;
import com.hhyx.execl.service.SystemMessageService;
import com.hhyx.execl.util.ListUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author MarkerCCC
 * @date 2019/6/18 - 9:40
 * @email markerccc@163.com
 */
@Slf4j
@Service
@SuppressWarnings("all")
public class FileImportServiceImpl implements FileImportService {

    @Autowired
    private BeforeFileService beforeFileService;

    @Autowired
    private SystemMessageService systemMessageService;
    //0代表正在处理 1代表处理成功  2 代表处理失败
    private int flag = 0;
    private List<Map<String, Object>> out;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Override
    public void readFolder(String pathStr, String localDateStr, HttpServletResponse response) {
        try {
            readFile(pathStr, localDateStr, response);
        } catch (IOException e) {
            log.error("{0}", e.getMessage());
        }
    }

    public void readFile(String pathStr, String localDateStr, HttpServletResponse response)
            throws IOException {

        // 存有文件名称的list
        Date date = new Date();
        LinkedList<String> fileNameLinkedList = new LinkedList<>();
        // Execl内容的List
        ArrayList<Map<String, Object>> mapArrayList = new ArrayList<>(10);

        // 读取文件
        test(pathStr, localDateStr, mapArrayList, fileNameLinkedList);

        // 开始遍历, 这个文件夹中有没有重复数据
        Map<String, Object> allRepeatedElements = ListUtils
                .findAllRepeatedElements(mapArrayList);
        // 这个集合装入所有的文件名
        ArrayList<String> fileList = new ArrayList<>(10);

        // 这个集合是装入所有的文件信息, 以及重复报错信息
        ArrayList<Map<String, Object>> streamList = new ArrayList<>(10);

        // 从中将信息装入两个集合中
        allRepeatedElements.entrySet().forEach(entry -> {
            if ("file".equals(entry.getKey())) {
                Set<String> value = (Set<String>) entry.getValue();
                // 做遍历删除操作?, 根据
                fileList.addAll(value);
            }
            Object value = entry.getValue();
            HashMap<String, Object> streamMap = new HashMap<>(16);
            streamMap.put("fileMessage", value);
            streamList.add(streamMap);
        });

        if (CollectionUtils.isNotEmpty(streamList)) {
            out = streamList;
            flag = 2;
        } else {
            flag = 1;
        }

        // 与数据库中的进行对比, 状态为删除状态, 时间为今天
        // 验证从这个文件夹中读出来的文件是不是0个
        if (CollectionUtils.isNotEmpty(fileNameLinkedList)) {
            // 得到版本号

            // 根据版本号, 与文件名称进行查询
            // 将集合中的文件名称与数据库中的数据进行比较, 如果有相同的才执行, 如果不相同, 就不允许修改
            List<SystemMessage> beforeOldList = null;
            List<Before> befores = new ArrayList<>(10);

            // 我想干嘛? 想将里面的数据的版本号进行+1
            for (Map<String, Object> stringObjectMap : mapArrayList) {
                Integer version = 0;
                Before before = BeanUtil.mapToBean(stringObjectMap, Before.class, true);
                String fileName = stringObjectMap.get("fileName").toString();
                QueryWrapper<SystemMessage> beforeQueryWrapper = new QueryWrapper<>();
                beforeQueryWrapper.eq("file_name", fileName)
                        .eq("del_flag", 1)
                        .eq("batch_number", localDateStr);
                beforeOldList = systemMessageService.list(beforeQueryWrapper);
                if (CollectionUtils.isNotEmpty(beforeOldList)) {
                    // 因为一个文件的版本的号都是一样的
                    version = Integer.valueOf(beforeOldList.get(0).getVersion());
                } else {
                    throw new BusinessException("请保证当前文件名与前一次提交一致");
                }
                ++version;
                before.setCreateTime(date)
                        .setUpdateTime(date)
                        .setVersion(version)
                        .setDelFlag(0)
                        .setBatchNumber(localDateStr)
                        .set下辖ID(StrUtil.cleanBlank(before.get下辖ID()));
                before.setId(0L);
                befores.add(before);
            }
            beforeFileService.saveBatch(befores);
            // ------------------ 开始存储对象End

            // 如果今天有, 我们就开始执行插入操作
            LinkedList<SystemMessage> systemMessageList = new LinkedList<>();

            // booleanList有数据, 就说明文件当好符合
            // 如果fileList为空, 就说明again文件夹里面是没有重复的
            if (CollectionUtils.isNotEmpty(fileList)) {
                befores.forEach(before -> {
                    SystemMessage systemMessage = new SystemMessage();
                    // 执行浅拷贝
                    BeanUtil.copyProperties(before, systemMessage);
                    if (systemMessage.get下辖ID().length() != 7) {
                        String errorStr =
                                "文件: " + before.getFileName() + "的 " + before.get下辖ID()
                                        + " id不完整, 请重新填写";
                        systemMessage.setError(errorStr);
                    }
                    systemMessage.setId(0L);
                    systemMessageList.add(systemMessage);
                });
                // 验证用户是否存在
                systemMessageService.verifyExistence(systemMessageList);
                // 进行去重
                Set<String> fileSet = new HashSet<>(fileList);
                systemMessageList.stream()
                        .filter(systemMessage -> StrUtil.isNotBlank(systemMessage.getError()))
                        .forEach(systemMessage -> {
                            fileSet.add(systemMessage.getFileName());
                        });
                fileSet.forEach(fileStr -> {
                    // 在fileList里面的, 都标记为删除状态
                    systemMessageList.stream()
                            .filter(before1 -> fileStr.equals(before1.getFileName()))
                            .forEach(before2 -> {
                                before2.setDelFlag(1);
                            });
                });
            } else {
                befores.forEach(before -> {
                    SystemMessage systemMessage = new SystemMessage();
                    if (before.get下辖ID().length() != 7) {
                        String errorStr =
                                "文件: " + before.getFileName() + "的 " + before.get下辖ID()
                                        + " id不完整, 请重新填写";
                        systemMessage.setError(errorStr).setDelFlag(1);
                    }

                    BeanUtil.copyProperties(before, systemMessage);
                    systemMessage.setId(0L);
                    systemMessageList.add(systemMessage);
                });
                // 验证用户是否存在
                systemMessageService.verifyExistence(systemMessageList);
            }
            systemMessageService.saveBatch(systemMessageList);
        } else {
            throw new BusinessException("重复提交无效");
        }
    }

    /**
     * 解析文件
     *
     * @param pathStr
     * @param localDateStr
     * @param mapArrayList
     * @param fileNameLinkedList
     * @throws IOException
     */
    public void test(String pathStr, String localDateStr,
            ArrayList<Map<String, Object>> mapArrayList, LinkedList<String> fileNameLinkedList)
            throws IOException {
        List<File> files = new ArrayList<>(10);

        Files.walkFileTree(Paths.get(pathStr), new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                    throws IOException {
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                    throws IOException {
                // threadPoolExecutor.execute(() -> {
                    String name = file.toFile().getName();
                    fileNameLinkedList.add(name);
                    String substring1 = name.substring(0, 2);
                    String substring = name.substring(name.lastIndexOf('.') + 1);
                    if (substring.contains("xl") && !substring1.contains("~$")) {
                        files.add(file.toFile());
                    }
                // });
                return super.visitFile(file, attrs);
            }
        });
        log.error("-----> {}", files.size());
        // CollUtil 判断交集
        files.forEach(file -> {
            log.error("进入");
            // 使用HuTool读取Execl, 先进行单个execl验证, 多条通过sql去验证
            ExcelReader reader = null;
            try {
                reader = ExcelUtil.getReader(file);
            } catch (Exception e) {
                log.error("{}", e.getMessage());
                log.error("fileName: ----------------->{}", file.getName());
                throw new BusinessException("文件被占用, 进程无法访问");
            }
            // 读取第一列的数据
            List<Object> objects = reader.readRow(0);

            // 拿到了所有的内容, 包括表头, 这里没一行都是一个Map
            List<Map<String, Object>> maps = reader.readAll();

            // 验证并保存数据
            int icount = 0;
            for (Map<String, Object> map : maps) {
                if (!map.containsKey("下辖ID")) {
                    log.error("------------------------------->{}", file.getName());
                    throw new BusinessException("缺少下辖ID列");
                }
                // 处理数据
                map.put("fileName", file.getName());
                map.put("row", icount);
                mapArrayList.add(map);
                log.error("{}", mapArrayList.size());
                ++icount;
            }
        });
    }

    @Override
    public Integer getResult(HttpServletResponse response) {
        return flag;
    }

    @Override
    public ServletOutputStream getResult1(HttpServletResponse response) {
        ReadFileResult rs = new ReadFileResult();
        ExcelWriter writer = ExcelUtil.getBigWriter();
        writer.addHeaderAlias("fileMessage", "文件信息");
        writer.write(out, true);
        log.error("-------->{}", out.toString());
        writer.setColumnWidth(-1, 15);
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=test.xlsx");
        ServletOutputStream servletOutputStream = null;
        try {
            servletOutputStream = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        writer.flush(servletOutputStream);
        writer.close();
        IoUtil.close(servletOutputStream);

        return servletOutputStream;
    }
}
